home *** CD-ROM | disk | FTP | other *** search
- /*
- * machCode.c --
- *
- * C code for the mach module.
- *
- * Copyright (C) 1989 Digital Equipment Corporation.
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies.
- * Digital Equipment Corporation makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/mach/ds3100.md/machCode.c,v 9.27 92/08/10 17:58:15 mgbaker Exp $ SPRITE (DECWRL)";
- #endif not lint
-
- #include <sprite.h>
- #include <stddef.h>
- #include <assert.h>
-
- #include <machConst.h>
- #include <machMon.h>
- #include <machInt.h>
- #include <mach.h>
- #include <sys.h>
- #include <sync.h>
- #include <dbg.h>
- #include <proc.h>
- #include <procMigrate.h>
- #include <procUnixStubs.h>
- #include <sched.h>
- #include <vm.h>
- #include <vmMach.h>
- #include <sig.h>
- #include <sigMach.h>
- #include <swapBuffer.h>
- #include <net.h>
- #include <ultrixSignal.h>
- #include <recov.h>
-
- /*
- * Conversion of function to an unsigned value.
- */
- #define F_TO_A (Address)(unsigned)(int (*)())
- /*
- * Number of processors in the system.
- */
- #ifndef NUM_PROCESSORS
- #define NUM_PROCESSORS 1
- #endif
-
- int mach_NumProcessors = NUM_PROCESSORS;
-
- /*
- * TRUE if cpu was in kernel mode before the interrupt, FALSE if was in
- * user mode.
- */
- Boolean mach_KernelMode;
-
- /*
- * Flag used by routines to determine if they are running at
- * interrupt level.
- */
- Boolean mach_AtInterruptLevel = FALSE;
-
- /*
- * The machine type string is imported by the file system and
- * used when expanding $MACHINE in file names.
- */
-
- char *mach_MachineType = "ds3100";
-
- extern int debugProcStubs;
-
- /*
- * The byte ordering/alignment type used with Fmt_Convert and I/O control data
- */
- Fmt_Format mach_Format = FMT_MIPS_FORMAT;
-
- /*
- * Count of number of ``calls'' to enable interrupts minus number of calls
- * to disable interrupts. Kept on a per-processor basis.
- */
- int mach_NumDisableInterrupts[NUM_PROCESSORS];
- int *mach_NumDisableIntrsPtr = mach_NumDisableInterrupts;
-
- /*
- * The format that the kernel stack has to be in to start a process off.
- */
- typedef struct {
- int magicNumber; /* Magic number used to determine if
- * the stack has been corrupted. */
- int statusReg; /* The status register value. */
- int filler[10]; /* Extra space on the stack to
- * store args and such. */
- } KernelStack;
-
- /*
- * The format of a signal stack that is pushed onto a user's stack when
- * a signal is handled.
- */
- typedef struct {
- Sig_Stack sigStack;
- Sig_Context sigContext;
- } SignalStack;
-
- /*
- * Machine dependent variables.
- */
- Address mach_KernStart;
- Address mach_CodeStart;
- Address mach_StackBottom;
- int mach_KernStackSize;
- Address mach_KernEnd;
- Address mach_FirstUserAddr;
- Address mach_LastUserAddr;
- Address mach_MaxUserStackAddr;
- int mach_LastUserStackPage;
-
- /*
- * The variables and tables below are used to dispatch kernel calls.
- */
-
- #define MAXCALLS 120
- #define MAXARGS 10
-
- int machMaxSysCall; /* Highest defined system call. */
- /*
- * Tables to determine where to go to fetch the arguments for a system call.
- */
- ReturnStatus (*machArgDispatch[MAXCALLS])();
- ReturnStatus (*machArgDispatchTable[])() = {
- MachFetch0Args,
- MachFetch0Args,
- MachFetch0Args,
- MachFetch0Args,
- MachFetch0Args,
- MachFetch1Arg,
- MachFetch2Args,
- MachFetch3Args,
- MachFetch4Args,
- MachFetch5Args,
- MachFetch6Args,
- };
-
- ReturnStatus (*(mach_NormalHandlers[MAXCALLS]))();
- /* For each system call, gives the
- * address of the routine to handle
- * the call for non-migrated processes.
- */
- ReturnStatus (*(mach_MigratedHandlers[MAXCALLS]))();
- /* For each system call, gives the
- * address of the routine to handle
- * the call for migrated processes. */
- int machKcallTableOffset; /* Byte offset of the kcallTable field
- * in a Proc_ControlBlock. */
- int machStatePtrOffset; /* Byte offset of the machStatePtr
- * field in a Proc_ControlBlock. */
- int machSpecialHandlingOffset; /* Byte offset of the specialHandling
- * field in a Proc_ControlBlock. */
- MachStringTable machMonBootParam; /* Parameters from boot line. */
- /*
- * Pointer to the state structure for the current process and the
- * current owner of the floating point unit.
- */
- Mach_State *machCurStatePtr = (Mach_State *)NIL;
- Mach_State *machFPCurStatePtr = (Mach_State *)NIL;
-
- extern Boolean Dev_SIIIntr();
- extern void Timer_TimerServiceInterrupt();
- extern void Dev_DC7085Interrupt();
- extern void MachFPInterrupt();
-
- extern void PrintError _ARGS_((void));
- static void PrintInst _ARGS_((unsigned pc, unsigned inst));
- static void SoftFPReturn _ARGS_((void));
- static void MemErrorInterrupt _ARGS_((void));
- static void CheckFastRestart _ARGS_((void));
-
- /*
- * The interrupt handler table. This originally was static, hence the
- * initialization here. It is now possible to set the entries
- * via Mach_SetHandler().
- */
- void (*machInterruptRoutines[MACH_NUM_HARD_INTERRUPTS])() = {
- (void (*)())Dev_SIIIntr,
- (void (*)())Net_Intr,
- Dev_DC7085Interrupt,
- Timer_TimerServiceInterrupt,
- MemErrorInterrupt,
- MachFPInterrupt,
- };
-
- ClientData machInterruptArgs[MACH_NUM_HARD_INTERRUPTS];
-
- extern void Mach_KernGenException();
- extern void Mach_UserGenException();
- extern void VmMach_KernTLBException();
- extern void VmMach_TLBModException();
- extern void VmMach_UTLBMiss();
- extern void VmMach_EndUTLBMiss();
-
- /*
- * The kernel exception handlers.
- */
- void (*machKernExcTable[])() = {
- Mach_KernGenException,
- VmMach_TLBModException,
- VmMach_KernTLBException,
- VmMach_KernTLBException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- Mach_KernGenException,
- };
-
- /*
- * The kernel exception handlers.
- */
- void (*machUserExcTable[])() = {
- Mach_UserGenException,
- VmMach_TLBModException,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- MachSysCall,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- Mach_UserGenException,
- };
-
- /*
- * Size of the instruction and data caches.
- */
- unsigned machDataCacheSize;
- unsigned machInstCacheSize;
-
- /*
- * The debugger structure.
- */
- Mach_DebugState mach_DebugState;
- Mach_DebugState *machDebugStatePtr = &mach_DebugState;
-
- static void SetupSigHandler _ARGS_((register Proc_ControlBlock *procPtr,
- register SignalStack *sigStackPtr, Address pc));
- static void ReturnFromSigHandler _ARGS_((register Proc_ControlBlock *procPtr));
- static ReturnStatus Interrupt _ARGS_((unsigned statusReg, unsigned causeReg,
- Address pc));
-
- /*
- * Preallocate all machine state structs.
- */
- Mach_State machStateTable[VMMACH_MAX_KERN_STACKS];
- int nextStateIndex = 0;
-
- /*
- * Save the bad address that caused an exception. This makes debugging
- * of TLB misses easier.
- */
-
- Address machBadVaddr = (Address) NIL;
-
- /*
- * Declarations of recovery-related items. For the decstations, most
- * of these are no-ops.
- *
- * The following two variables should be in the initialized ata space, but
- * marked as not initialized. Then , when they are updated as part of booting,
- * their new values get preserved over a fast restart.
- */
- int storedDataSize = -1; /* Not initialized. */
- char *mach_RestartTablePtr = (char *) NIL;
- char storedData[1]; /* A no-op for now. */
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_Init --
- *
- * Initialize the exception vector table and some of the dispatching
- * tables.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The exception vector table is initialized.
- *
- * ----------------------------------------------------------------------------
- */
- void
- Mach_Init(boot_argc,boot_argv)
- int boot_argc; /* Argc from boot sequence. */
- MachStringTable *boot_argv; /* Boot sequence strings. */
- {
- extern char end[], edata[];
- int offset, i;
- char buf[256];
-
- /*
- * Zero out the bss segment.
- */
- bzero(edata, end - edata);
-
- /*
- * Set exported machine dependent variables.
- */
- mach_KernStart = (Address)MACH_KERN_START;
- mach_KernEnd = (Address)MACH_KERN_END;
- mach_CodeStart = (Address)MACH_CODE_START;
- mach_StackBottom = (Address)MACH_STACK_BOTTOM;
- mach_KernStackSize = MACH_KERN_STACK_SIZE;
- mach_FirstUserAddr = (Address)MACH_FIRST_USER_ADDR;
- mach_LastUserAddr = (Address)MACH_LAST_USER_ADDR;
- mach_MaxUserStackAddr = (Address)MACH_MAX_USER_STACK_ADDR;
- mach_LastUserStackPage = (MACH_MAX_USER_STACK_ADDR - 1) / VMMACH_PAGE_SIZE;
-
- /*
- * Copy the boot parameter structure. The original location will get
- * unmapped during vm initialization so we need to get our own copy.
- * Depending on how the machine was booted, the boot arguments
- * may or may not be parsed. So we'll glob them all together and
- * then parse them.
- */
- buf[0] = '\0';
- for (i = 0; i < boot_argc; i++) {
- strcat(buf,boot_argv->argPtr[i]);
- strcat(buf," ");
- }
- Mach_ArgParse(buf,&machMonBootParam);
-
- /*
- * Initialize some of the dispatching information. The rest is
- * initialized by Mach_InitSysCall below.
- */
- machMaxSysCall = -1;
- machKcallTableOffset = (int) &((Proc_ControlBlock *) 0)->kcallTable;
- machStatePtrOffset = (int) &((Proc_ControlBlock *) 0)->machStatePtr;
- machSpecialHandlingOffset = (int)
- &((Proc_ControlBlock *) 0)->specialHandling;
-
- /*
- * We start off with interrupts disabled.
- */
- mach_NumDisableInterrupts[0] = 1;
-
- /*
- * Copy down exception vector code.
- */
- if (F_TO_A VmMach_EndUTLBMiss - F_TO_A VmMach_UTLBMiss > 0x80) {
- panic("Mach_Init: UTLB code too large\n");
- }
- bcopy(F_TO_A VmMach_UTLBMiss, F_TO_A MACH_UTLB_MISS_EXC_VEC,
- F_TO_A VmMach_EndUTLBMiss - F_TO_A VmMach_UTLBMiss);
- bcopy(F_TO_A MachException, (Address)MACH_GEN_EXC_VEC,
- F_TO_A MachEndException - F_TO_A MachException);
-
- if (recov_Transparent) {
- CheckFastRestart();
- }
- /*
- * Clear out the i and d caches.
- */
- Mach_MonPrintf("Configuring cache: ");
- MachConfigCache();
- Mach_MonPrintf("data cache size =%x inst cache size=%x\n",
- machDataCacheSize, machInstCacheSize);
- MachFlushCache();
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_SetHandler --
- *
- * Put a interrupt handling routine into the table.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The interrupt handling table is modified.
- *
- * ----------------------------------------------------------------------------
- */
-
- void
- Mach_SetHandler(interruptNumber, handler, clientData)
- int interruptNumber; /* Interrupt number to set */
- void (*handler)(); /* Interrupt handling procedure */
- ClientData clientData; /* ClientData for interrupt callback routine. */
- {
- /*
- * Check that it is valid. Can't override FPU interrupt because it
- * takes special parameters.
- */
- if ((interruptNumber < 0) || (interruptNumber >= MACH_NUM_HARD_INTERRUPTS)){
- panic("Warning: Bad interrupt number %d\n",interruptNumber);
- } else {
- machInterruptRoutines[interruptNumber] = handler;
- machInterruptArgs[interruptNumber] = clientData;
- }
- }
-
- static Vm_ProcInfo mainProcInfo;
- static Mach_State mainMachState;
- static VmMach_ProcData mainProcData;
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_InitFirstProc --
- *
- * Initialize the machine state struct for the very first process.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Machine info allocated and stack start set up.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_InitFirstProc(procPtr)
- Proc_ControlBlock *procPtr;
- {
-
- assert(offsetof(Proc_ControlBlock, unixErrno) == MACH_UNIX_ERRNO_OFFSET);
- procPtr->machStatePtr = &mainMachState;
- procPtr->machStatePtr->kernStackStart = mach_StackBottom;
- procPtr->machStatePtr->kernStackEnd =
- (mach_StackBottom + mach_KernStackSize);
- /*
- * Set up the TLB entries. This code depends
- * implictly upon MACH_KERN_STACK_PAGES.
- */
- procPtr->machStatePtr->tlbHighEntry = 0;
- procPtr->machStatePtr->tlbLowEntries[0] = 0;
- procPtr->machStatePtr->tlbLowEntries[1] = 0;
- procPtr->machStatePtr->tlbLowEntries[2] = 0;
- procPtr->vmPtr = &mainProcInfo;
- procPtr->vmPtr->machPtr = &mainProcData;
- VmMach_ProcInit(&mainProcInfo);
- machCurStatePtr = procPtr->machStatePtr;
- VmMach_SetupContext(procPtr);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_SetupNewState --
- *
- * Initialize the machine state for this process. This includes
- * allocating and initializing a kernel stack. Assumed that will
- * be called when starting a process after a fork or restarting a
- * process after a migration.
- *
- * Results:
- * PROC_NO_STACKS if couldn't allocate a kernel stack. SUCCESS otherwise.
- *
- * Side effects:
- * Machine state in the destination process control block is overwritten.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Mach_SetupNewState(procPtr, fromStatePtr, startFunc, startPC, user)
- Proc_ControlBlock *procPtr; /* Pointer to process control block
- * to initialize state for. */
- Mach_State *fromStatePtr; /* State of parent on fork or from
- * other machine on migration. */
- void (*startFunc)(); /* Function to call when process first
- * starts executing. */
- Address startPC; /* Address to pass as argument to
- * startFunc. If NIL then the address
- * is taken from *fromStatePtr's
- * exception stack. */
- Boolean user; /* TRUE if is a user process. */
- {
- register KernelStack *stackPtr;
- register Mach_State *statePtr;
- unsigned virtPage;
-
- if (procPtr->machStatePtr == (Mach_State *)NIL) {
- procPtr->machStatePtr = &machStateTable[nextStateIndex];
- nextStateIndex++;
- if (nextStateIndex >= VMMACH_MAX_KERN_STACKS) {
- panic("Mach_SetupNewState: Out of machine state structs\n");
- }
- }
-
- statePtr = procPtr->machStatePtr;
- /*
- * Allocate a kernel stack for this process.
- */
- statePtr->kernStackStart = Vm_GetKernelStack(0);
- if (statePtr->kernStackStart == (Address)NIL) {
- return(PROC_NO_STACKS);
- }
- statePtr->kernStackEnd = statePtr->kernStackStart + MACH_KERN_STACK_SIZE;
- /*
- * Set up the TLB entries. This code depends
- * implictly upon MACH_KERN_STACK_PAGES.
- */
- virtPage = (unsigned)(statePtr->kernStackStart + VMMACH_PAGE_SIZE) >>
- VMMACH_PAGE_SHIFT;
- statePtr->tlbHighEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
- (VMMACH_KERN_PID << VMMACH_TLB_PID_SHIFT);
- virtPage -= VMMACH_VIRT_CACHED_START_PAGE;
- statePtr->tlbLowEntries[0] = vmMach_KernelTLBMap[virtPage];
- statePtr->tlbLowEntries[1] = vmMach_KernelTLBMap[virtPage + 1];
- statePtr->tlbLowEntries[2] = vmMach_KernelTLBMap[virtPage + 2];
-
- statePtr->switchRegState.regs[SP] =
- (unsigned)(statePtr->kernStackEnd - sizeof(KernelStack));
- /*
- * Initialize the stack so that it looks like it is in the middle of
- * Mach_ContextSwitch.
- */
- stackPtr = (KernelStack *)(statePtr->switchRegState.regs[SP]);
- stackPtr->magicNumber = MAGIC;
- stackPtr->statusReg = 0;
- statePtr->switchRegState.regs[RA] = (unsigned)startFunc;
- /*
- * Set up the user's stack pointer.
- */
- statePtr->userState.regState.regs[SP] = (unsigned)mach_MaxUserStackAddr;
- /*
- * Set up the state of the process. User processes inherit from their
- * parent or the migrated process. If the PC is not specified, take it
- * from the parent as well.
- */
- if (user) {
- bcopy((Address)&fromStatePtr->userState,
- (Address)&statePtr->userState,
- sizeof(statePtr->userState));
- statePtr->userState.regState.pc += 4;
- }
- if (startPC == (Address)NIL) {
- statePtr->switchRegState.regs[A0] =
- (unsigned)fromStatePtr->userState.regState.pc + 4;
- } else {
- statePtr->switchRegState.regs[A0] = (unsigned)startPC;
- }
- statePtr->userState.regState.fpStatusReg = 0;
-
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_SetReturnVal --
- *
- * Set the return value for a process from a system call. Intended to
- * be called by the routine that starts a user process after a fork.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Register D0 is set in the user registers.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_SetReturnVal(procPtr, retVal, retVal2)
- Proc_ControlBlock *procPtr; /* Process to set return value for. */
- int retVal; /* Value for process to return. */
- int retVal2; /* Second return value. */
- {
- procPtr->machStatePtr->userState.regState.regs[V0] = (unsigned)retVal;
- procPtr->machStatePtr->userState.regState.regs[V1] = (unsigned)retVal2;
- }
-
- /*----------------------------------------------------------------------------
- *
- * Mach_Return2 --
- *
- * Set the second return value for Unix compat. routines that
- * return two values.
- *
- * Results:
- * None.
- *
- * Side effects:
- * v1 <- val
- *
- *----------------------------------------------------------------------------
- */
- void
- Mach_Return2(val)
- int val;
- {
- Proc_GetActualProc()->machStatePtr->userState.regState.regs[V1] =
- (unsigned)val;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_StartUserProc --
- *
- * Start a user process executing for the first time.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Stack pointer and the program counter set for the process and
- * the current process's image is replaced.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_StartUserProc(procPtr, entryPoint)
- Proc_ControlBlock *procPtr; /* Process control block for process
- * to start. */
- Address entryPoint; /* Where process is to start
- * executing. */
- {
- register Mach_State *statePtr;
-
- statePtr = procPtr->machStatePtr;
- statePtr->userState.regState.pc = entryPoint;
- (void)MachUserReturn(procPtr);
-
- MachRunUserProc(entryPoint, statePtr->userState.regState.regs[SP]);
- /* THIS DOES NOT RETURN */
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_ExecUserProc --
- *
- * Replace the calling user process's image with a new one.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Stack pointer set for the process.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_ExecUserProc(procPtr, userStackPtr, entryPoint)
- Proc_ControlBlock *procPtr; /* Process control block for
- * process to exec. */
- Address userStackPtr; /* Stack pointer for when the
- * user process resumes
- * execution. */
- Address entryPoint; /* Where the user process is
- * to resume execution. */
- {
- procPtr->machStatePtr->userState.regState.regs[SP] =
- (unsigned)userStackPtr;
- Mach_StartUserProc(procPtr, entryPoint);
- /* THIS DOES NOT RETURN */
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_FreeState --
- *
- * Free up the machine state for the given process control block.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Free up the kernel stack.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_FreeState(procPtr)
- Proc_ControlBlock *procPtr; /* Process control block to free
- * machine state for. */
- {
- if (procPtr->machStatePtr->kernStackStart != (Address)NIL) {
- Vm_FreeKernelStack(procPtr->machStatePtr->kernStackStart);
- procPtr->machStatePtr->kernStackStart = (Address)NIL;
- }
- if (procPtr->machStatePtr == machFPCurStatePtr) {
- machFPCurStatePtr = (Mach_State *)NIL;
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_CopyState --
- *
- * Copy the state from the given state structure to the machine
- * state structure for the destination process control block. Intended
- * to be used by the debugger to modify the state.The only fields
- * that can be modified are the following:
- *
- * 1) user stack pointer
- * 2) all trap registers except for the stack pointer because the
- * stack pointer in the trap registers is the kernel stack pointer.
- * 3) the PC, VOR and status register in the exception stack.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Machine state in the destination process control block is overwritten.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_CopyState(statePtr, destProcPtr)
- Mach_State *statePtr; /* Pointer to state to copy from. */
- Proc_ControlBlock *destProcPtr; /* Process control block to copy
- * state to. */
- {
- bcopy((Address)&statePtr->userState,
- (Address)&destProcPtr->machStatePtr->userState,
- sizeof(statePtr->userState));
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_GetDebugState --
- *
- * Extract the appropriate fields from the machine state struct
- * and store them into the debug struct.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Debug struct filled in from machine state struct.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_GetDebugState(procPtr, debugStatePtr)
- Proc_ControlBlock *procPtr;
- Proc_DebugState *debugStatePtr;
- {
- register Mach_State *machStatePtr;
-
- machStatePtr = procPtr->machStatePtr;
- bcopy((Address)machStatePtr->userState.regState.regs,
- (Address)debugStatePtr->regState.regs,
- sizeof(machStatePtr->userState.regState.regs));
- debugStatePtr->regState.pc = machStatePtr->userState.regState.pc;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_SetDebugState --
- *
- * Extract the appropriate fields from the debug struct
- * and store them into the machine state struct.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Machine state struct filled in from the debug state struct.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_SetDebugState(procPtr, debugStatePtr)
- Proc_ControlBlock *procPtr;
- Proc_DebugState *debugStatePtr;
- {
- register Mach_State *machStatePtr;
-
- machStatePtr = procPtr->machStatePtr;
- bcopy((Address)debugStatePtr->regState.regs,
- (Address)machStatePtr->userState.regState.regs,
- sizeof(machStatePtr->userState.regState.regs));
- machStatePtr->userState.regState.pc = debugStatePtr->regState.pc;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_GetUserStackPtr --
- *
- * Return the user stack pointer from the machine state struct for the
- * given process.
- *
- * Results:
- * The value of the user stack pointer when the process trapped.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- Address
- Mach_GetUserStackPtr(procPtr)
- Proc_ControlBlock *procPtr;
- {
- return((Address)procPtr->machStatePtr->userState.regState.regs[SP]);
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_GetStackPointer --
- *
- * Return the value of the stack pointer.
- *
- * Results:
- * The value of the user's stack pointer.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- Address
- Mach_GetStackPointer(procPtr)
- Proc_ControlBlock *procPtr;
- {
- return((Address)procPtr->machStatePtr->userState.regState.regs[SP]);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_InitSyscall --
- *
- * During initialization, this procedure is called once for each
- * kernel call, in order to set up information used to dispatch
- * the kernel call. This procedure must be called once for each
- * kernel call, in order starting at 0.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Initializes the dispatch tables for the kernel call.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_InitSyscall(callNum, numArgs, normalHandler, migratedHandler)
- int callNum; /* Number of the system call. */
- int numArgs; /* Number of one-word arguments passed
- * into call on stack. */
- ReturnStatus (*normalHandler)(); /* Procedure to process kernel call
- * when process isn't migrated. */
- ReturnStatus (*migratedHandler)(); /* Procedure to process kernel call
- * for migrated processes. */
- {
- machMaxSysCall++;
- if (machMaxSysCall != callNum) {
- printf("Warning: out-of-order kernel call initialization, call %d\n",
- callNum);
- }
- if (machMaxSysCall >= MAXCALLS) {
- printf("Warning: too many kernel calls.\n");
- machMaxSysCall--;
- return;
- }
- if (numArgs > MAXARGS) {
- printf("Warning: too many arguments to kernel call %d\n", callNum);
- numArgs = MAXARGS;
- }
- machArgDispatch[machMaxSysCall] = machArgDispatchTable[numArgs];
- mach_NormalHandlers[machMaxSysCall] = normalHandler;
- mach_MigratedHandlers[machMaxSysCall] = migratedHandler;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * MachUserExceptionHandler --
- *
- * Handle a user exception.
- *
- * Results:
- * TRUE if should enable the floating point coprocessor.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- Boolean
- MachUserExceptionHandler(statusReg, causeReg, badVaddr, pc)
- unsigned statusReg; /* The status register at the time of the
- * exception. */
- unsigned causeReg; /* The cause register - contains the type
- * of exception. */
- Address badVaddr; /* The address (if any) that the fault
- * occured on. */
- Address pc; /* Program counter where to continue. */
- {
- register Proc_ControlBlock *procPtr;
- int cause;
- Boolean retVal;
- ReturnStatus status;
-
- machBadVaddr = badVaddr;
- cause = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT;
- if (cause != MACH_EXC_INT) {
- Mach_EnableIntr();
- }
-
- procPtr = Proc_GetActualProc();
- switch (cause) {
- case MACH_EXC_INT:
- status = Interrupt(statusReg, causeReg, pc);
- if (status != MACH_OK) {
- panic("MachUserExceptionHandler: nested interrupts.\n");
- }
- /*
- * Enable interrupts so that we can do the user mode return
- * checks.
- */
- Mach_EnableIntr();
- break;
- case MACH_EXC_TLB_MOD:
- if (VmMach_TLBModFault(badVaddr) != SUCCESS) {
- printf("Protection fault in process %x: pc=%x addr=%x\n",
- procPtr->processID, pc, badVaddr);
- (void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
- procPtr->processID, FALSE, badVaddr);
- }
- break;
- case MACH_EXC_TLB_LD_MISS:
- case MACH_EXC_TLB_ST_MISS:
- if (VmMach_TLBFault(badVaddr) != SUCCESS) {
- printf("Bad user TLB fault in process %x: pc=%x addr=%x\n",
- procPtr->processID, pc, badVaddr);
- (void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
- procPtr->processID, FALSE, badVaddr);
- }
- break;
- case MACH_EXC_ADDR_ERR_LD:
- case MACH_EXC_ADDR_ERR_ST:
- printf("Address fault in process %x: pc=%x addr=%x\n",
- procPtr->processID, pc, badVaddr);
- (void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
- procPtr->processID, FALSE, badVaddr);
- break;
- case MACH_EXC_BUS_ERR_IFETCH:
- printf("MachExceptionHandler: User bus error on ifetch");
- (void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
- procPtr->processID, FALSE, badVaddr);
- break;
- case MACH_EXC_BUS_ERR_LD_ST:
- printf("MachExceptionHandler: User bus error on ld or st");
- (void) Sig_Send(SIG_ADDR_FAULT, SIG_ACCESS_VIOL,
- procPtr->processID, FALSE, badVaddr);
- break;
- case MACH_EXC_SYSCALL:
- if (!MachUNIXSyscallNew()) {
- printf("MachExceptionHandler: Bad syscall magic for proc %x\n",
- procPtr->processID);
- (void) Sig_Send(SIG_ILL_INST, SIG_BAD_TRAP,
- procPtr->processID, FALSE, pc);
- }
- break;
- case MACH_EXC_BREAK: {
- unsigned inst;
- /*
- * Check to see if this is a return from signal handler
- * break or a normal breakpoint.
- */
- if (Vm_CopyIn(sizeof(int), pc, (Address)&inst) != SUCCESS) {
- panic("MachExceptionHandler: Couldn't fetch break inst.");
- }
- #if 0
- printf("Pc = 0x%x, Instruction = 0x%x\n", pc, inst);
- printf("Cause register = 0x%x\n", causeReg);
- #endif
- switch ((int)(inst & MACH_BREAK_CODE_FIELD)) {
- case MACH_BREAKPOINT_VAL:
- Proc_Lock(procPtr);
- if (procPtr->genFlags & PROC_DEBUG_ON_EXEC) {
- procPtr->genFlags &= ~PROC_DEBUG_ON_EXEC;
- (void) Sig_SendProc(procPtr, SIG_DEBUG,
- SIG_NO_CODE, pc);
- } else {
- (void) Sig_SendProc(procPtr, SIG_BREAKPOINT,
- SIG_NO_CODE, pc);
- }
- Proc_Unlock(procPtr);
- break;
- case MACH_SSTEP_VAL: {
- ReturnStatus status;
-
- Vm_ChangeCodeProt(procPtr, pc, 4, TRUE);
- status = Vm_CopyOut(4, (Address)&machCurStatePtr->sstepInst, pc);
- Vm_ChangeCodeProt(procPtr, pc, 4, FALSE);
- Vm_FlushCode(procPtr, pc, 4);
- if (status != SUCCESS) {
- panic("MachUserExceptionHandler: Bad sstep PC\n");
- }
- Proc_Lock(procPtr);
- (void) Sig_SendProc(procPtr, SIG_TRACE_TRAP, SIG_NO_CODE,
- pc);
- Proc_Unlock(procPtr);
- break;
- }
-
- case MACH_SIG_RET_VAL:
- ReturnFromSigHandler(procPtr);
- break;
- default:
- printf("Bogus bp-trap\n");
- (void) Sig_Send(SIG_ILL_INST, SIG_ILL_INST_CODE,
- procPtr->processID, FALSE, pc);
- break;
- }
- break;
- }
- case MACH_EXC_RES_INST:
- printf("Reserved instruction in process %x at pc=%x\n",
- procPtr->processID, pc);
- (void) Sig_Send(SIG_ILL_INST, SIG_ILL_INST_CODE,
- procPtr->processID, FALSE, pc);
- break;
- case MACH_EXC_COP_UNUSABLE:
- MachSwitchFPState(machFPCurStatePtr, machCurStatePtr);
- machFPCurStatePtr = machCurStatePtr;
- break;
- case MACH_EXC_OVFLOW:
- printf("Overflow exception in process %x at pc=%x\n",
- procPtr->processID, pc);
- (void) Sig_Send(SIG_ARITH_FAULT, SIG_OVERFLOW,
- procPtr->processID, FALSE, pc);
- break;
- }
- retVal = MachUserReturn(procPtr);
-
- return(retVal);
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * MachKernelExceptionHandler --
- *
- * Handle a kernel exception.
- *
- * Results:
- * MACH_KERN_ERROR if the debugger should be called after this routine
- * returns, MACH_USER_ERROR if a copy to/from user space caused an
- * unrecoverable bus error, and MACH_OK if everything worked out ok.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- int
- MachKernelExceptionHandler(statusReg, causeReg, badVaddr, pc)
- unsigned statusReg; /* The status register at the time of the
- * exception. */
- unsigned causeReg; /* The cause register - contains the type
- * of exception. */
- Address badVaddr; /* The address (if any) that the fault
- * occured on. */
- Address pc; /* Program counter where to continue. */
- {
- register Proc_ControlBlock *procPtr;
- ReturnStatus status;
- int cause;
-
- cause = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT;
- machBadVaddr = badVaddr;
-
- /*
- * Process kernel traps.
- */
- procPtr = Proc_GetActualProc();
- switch (cause) {
- case MACH_EXC_INT:
- status = Interrupt(statusReg, causeReg, pc);
- return(status);
- case MACH_EXC_TLB_LD_MISS:
- case MACH_EXC_TLB_ST_MISS:
- case MACH_EXC_TLB_MOD: {
- Boolean copyInProgress = FALSE;
-
- if (statusReg & MACH_SR_INT_ENA_PREV) {
- /*
- * Enable interrupts.
- */
- Mach_EnableIntr();
- }
-
- if (pc >= F_TO_A Vm_CopyIn && pc < F_TO_A VmMachCopyEnd) {
- copyInProgress = TRUE;
- } else if (pc >= F_TO_A MachFetchArgs &&
- pc <= F_TO_A MachFetchArgsEnd) {
- copyInProgress = TRUE;
- } else if (badVaddr < (Address)VMMACH_VIRT_CACHED_START &&
- (badVaddr >= (Address)VMMACH_PHYS_CACHED_START ||
- procPtr == (Proc_ControlBlock *)NIL ||
- procPtr->vmPtr->numMakeAcc == 0)) {
- if (procPtr != (Proc_ControlBlock *)NIL) {
- printf("%s: note: procPtr->vmPtr->numMakeAcc = %d\n",
- "MachKernelExceptionHandler",
- procPtr->vmPtr->numMakeAcc);
- }
- return(MACH_KERN_ERROR);
- }
- if (((causeReg & MACH_CR_EXC_CODE) >>
- MACH_CR_EXC_CODE_SHIFT) == MACH_EXC_TLB_MOD) {
- status = VmMach_TLBModFault(badVaddr);
- } else {
- status = VmMach_TLBFault(badVaddr);
- }
- if (status != SUCCESS) {
- if (copyInProgress) {
- return(MACH_USER_ERROR);
- } else {
- printf("badVaddr = 0x%x\n", badVaddr);
- return(MACH_KERN_ERROR);
- }
- } else {
- return(MACH_OK);
- }
- }
-
- case MACH_EXC_ADDR_ERR_LD:
- printf("MachKernelExceptionHandler: %s: addr: %x PC: %x\n",
- "Address error on load", badVaddr, pc);
- return(MACH_KERN_ERROR);
- case MACH_EXC_ADDR_ERR_ST:
- printf("MachKernelExceptionHandler: Address error on store\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_BUS_ERR_IFETCH:
- printf("MachKernelExceptionHandler: Bus error on ifetch\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_BUS_ERR_LD_ST:
- if (pc >= F_TO_A Mach_Probe &&
- pc <= F_TO_A MachProbeEnd) {
- return(MACH_USER_ERROR);
- }
- printf("MachKernelExceptionHandler: Bus error on load or store\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_SYSCALL:
- printf("MachKernelExceptionHandler: System call in kernel mode\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_BREAK:
- return(MACH_KERN_ERROR);
- case MACH_EXC_RES_INST:
- printf("MachKernelExceptionHandler: Reserved instruction\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_COP_UNUSABLE:
- printf("MachKernelExceptionHandler: Coprocessor unusable\n");
- return(MACH_KERN_ERROR);
- case MACH_EXC_OVFLOW:
- printf("MachKernelExceptionHandler: Overflow\n");
- return(MACH_KERN_ERROR);
- default:
- printf("MachKernelExceptionHandler: Unknown exception\n");
- return(MACH_KERN_ERROR);
- }
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Interrupt --
- *
- * Call the proper interrupt handler for the given interrupt.
- *
- * Results:
- * MACH_KERN_ERROR if the machine should go into the debugger, or MACH_OK
- * otherwise.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- #define DEBUG_INTR
- #ifdef DEBUG_INTR
- static int lastInterruptCalled = -1;
- #endif /* DEBUG_INTR */
-
-
- static ReturnStatus
- Interrupt(statusReg, causeReg, pc)
- unsigned statusReg;
- unsigned causeReg;
- Address pc;
- {
- int n;
- unsigned mask;
-
- #ifdef DEBUG_INTR
- if (mach_AtInterruptLevel) {
- printf("Received interrupt while at interrupt level.\n");
- }
- if (mach_NumDisableIntrsPtr[0] > 0) {
- printf("Received interrupt with mach_NumDisableIntrsPtr[0] = %d.\n",
- mach_NumDisableIntrsPtr[0]);
- }
- #endif /* DEBUG_INTR */
-
- mach_KernelMode = !(statusReg & MACH_SR_KU_PREV);
- mach_AtInterruptLevel = 1;
- n = 0;
- mask = (causeReg & statusReg & MACH_CR_INT_PENDING) >>
- MACH_CR_HARD_INT_SHIFT;
- while (mask != 0) {
- if (mask & 1) {
- #ifdef DEBUG_INTR
- if (n >= MACH_NUM_HARD_INTERRUPTS) {
- printf("Bogus index (%d) for interrupt handler\n", n);
- mach_AtInterruptLevel = 0;
- return(MACH_KERN_ERROR);
- }
- lastInterruptCalled = n;
- #endif /* DEBUG_INTR */
- /*
- * Interrupt 5, the FPU interrupt, requires the status, cause, and pc.
- * These values may have changed in the registers, during a call to
- * another interrupt handler, so we have to hand the routine the original
- * values.
- *
- * Interrupt 3, the timer interrupt, requires this stuff too, so it
- * can record the pc for profiling.
- */
- if (n == 3 || n==5) {
- machInterruptRoutines[n](statusReg, causeReg, pc);
- } else {
- machInterruptRoutines[n](machInterruptArgs[n]);
- }
- }
- mask >>= 1;
- n++;
- }
-
- mach_AtInterruptLevel = 0;
- #ifdef DEBUG_INTR
- lastInterruptCalled = -1;
- #endif /* DEBUG_INTR */
- return(MACH_OK);
- }
-
- /*
- * ----------------------------------------------------------------------------
- *
- * MachUserReturn --
- *
- * Take the proper action to return from a user exception.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Interrupts disabled.
- *
- * ----------------------------------------------------------------------------
- */
- Boolean
- MachUserReturn(procPtr)
- register Proc_ControlBlock *procPtr;
- {
- SignalStack sigStack;
- Address pc;
- int restarted = 0;
- Address savePC;
-
-
- if (procPtr->Prof_Scale >= 2 && procPtr->Prof_PC != 0) {
- Prof_RecordPC(procPtr);
- }
-
- if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
- procPtr->unixProgress != PROC_PROGRESS_UNIX && debugProcStubs) {
- printf("UnixProgress = %d entering MachUserReturn\n",
- procPtr->unixProgress);
- }
-
- /*
- * Take a context switch if one is pending for this process.
- */
- if (procPtr->schedFlags & SCHED_CONTEXT_SWITCH_PENDING) {
- Sched_LockAndSwitch();
- }
-
- while (TRUE) {
- /*
- * See if we are supposed to single-step this process. If so
- * put a break in the proper place. Don't worry if we miss a signal
- * because we will be back in real soon anyway (after one instruction).
- */
- if (procPtr->genFlags & PROC_SINGLE_STEP_FLAG) {
- Address breakPC;
- unsigned breakInst;
- ReturnStatus status;
- int accLen;
- Address newAddr;
-
- if (machFPCurStatePtr == machCurStatePtr) {
- MachGetCurFPState(machCurStatePtr);
- }
- Vm_MakeAccessible(VM_READONLY_ACCESS, sizeof(Address),
- machCurStatePtr->userState.regState.pc,
- &accLen, &newAddr);
- if (accLen != sizeof(Address)) {
- printf("MachUserReturn: Can't fetch user's trap PC\n");
- break;
- }
- breakPC = (Address)
- MachEmulateBranch(machCurStatePtr->userState.regState.regs,
- machCurStatePtr->userState.regState.pc,
- machCurStatePtr->userState.regState.fpStatusReg,
- TRUE);
- Vm_MakeUnaccessible(newAddr, sizeof(Address));
- if (Vm_CopyIn(4, breakPC,
- (Address)&machCurStatePtr->sstepInst) != SUCCESS) {
- printf("Bad single-step address\n");
- } else {
- breakInst = MACH_SSTEP_VAL | 0xd;
- Vm_ChangeCodeProt(procPtr, breakPC, 4, TRUE);
- status = Vm_CopyOut(4, (Address)&breakInst, breakPC);
- Vm_ChangeCodeProt(procPtr, breakPC, 4, FALSE);
- Vm_FlushCode(procPtr, breakPC, 4);
- if (status != SUCCESS) {
- printf("Bad single-step address\n");
- }
- }
- procPtr->genFlags &= ~PROC_SINGLE_STEP_FLAG;
- Mach_DisableIntr();
- break;
- } else {
- if (procPtr->unixProgress == PROC_PROGRESS_RESTART ||
- procPtr->unixProgress > 0) {
- /*
- * If we received a normal signal, we want to restart
- * the system call when we leave.
- * If we received a migrate signal, we will get here on
- * the new machine.
- */
-
- /*
- * Mangle the PC so we restart the trap after we leave
- * the kernel.
- */
- restarted = 1;
- if (debugProcStubs) {
- printf("Restarting system call with progress %d\n",
- procPtr->unixProgress);
- }
- }
- /*
- * Disable interrupts. Note that we don't use the DISABLE_INTR
- * macro because it increments the nesting depth of interrupts
- * which we don't want because there is an implicit enable
- * interrupts on rte.
- */
- Mach_DisableIntr();
- if (!Sig_Pending(procPtr)) {
- break;
- }
- Mach_EnableIntr();
- savePC = machCurStatePtr->userState.regState.pc;
- if (restarted) {
- /*
- * We have to move the PC now so the migrated process
- * will start in the right place.
- * If we don't migrate, we put the PC back after the
- * Sig_Handle.
- */
- machCurStatePtr->userState.regState.pc -= 4;
- }
- sigStack.sigStack.contextPtr = &sigStack.sigContext;
- if (Sig_Handle(procPtr, &sigStack.sigStack, &pc)) {
- SetupSigHandler(procPtr, &sigStack, pc);
- Mach_DisableIntr();
- break;
- } else {
- if (procPtr->unixProgress == PROC_PROGRESS_MIG_RESTART ||
- procPtr->unixProgress == PROC_PROGRESS_RESTART) {
- restarted = 1;
- if (debugProcStubs) {
- printf("No signal action, so we restarted call\n");
- }
- } else if (restarted && debugProcStubs) {
- printf("No signal, yet we restarted system call!\n");
- }
- }
- /*
- * Restore PC if we didn't migrate.
- */
- machCurStatePtr->userState.regState.pc = savePC;
- }
- }
-
- /*
- * It is possible for Sig_Handle to mask the migration signal
- * if a process is not in a state where it can be migrated.
- * As soon as we return to user mode, though, we will allow migration.
- */
- Sig_AllowMigration(procPtr);
-
- if (restarted) {
- procPtr->unixProgress = PROC_PROGRESS_UNIX;
- if (debugProcStubs) {
- printf("Moving the PC to restart the system call\n");
- printf("Our PC = %x\n",
- machCurStatePtr->userState.regState.pc);
- }
- machCurStatePtr->userState.regState.pc -= 4;
- if (debugProcStubs) {
- printf("Now our PC = %x\n",
- machCurStatePtr->userState.regState.pc);
- printf("V0 was %d and our call was %d\n",
- machCurStatePtr->userState.regState.regs[V0],
- machCurStatePtr->userState.unixRetVal);
- printf("Our incoming a0-a3 were %x %x %x %x\n",
- machCurStatePtr->userState.regState.regs[A0],
- machCurStatePtr->userState.regState.regs[A1],
- machCurStatePtr->userState.regState.regs[A2],
- machCurStatePtr->userState.regState.regs[A3]);
- }
- /*
- * Our V0 and A3 will have been clobbered by the system call, so
- * we have to restore them.
- */
- machCurStatePtr->userState.regState.regs[V0] =
- machCurStatePtr->userState.savedV0;
- machCurStatePtr->userState.regState.regs[A3] =
- machCurStatePtr->userState.savedA3;
- }
-
- if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX &&
- procPtr->unixProgress != PROC_PROGRESS_UNIX) {
- procPtr->unixProgress = PROC_PROGRESS_UNIX;
- if (debugProcStubs) {
- printf("UnixProgress = %d leaving MachUserReturn!\n",
- procPtr->unixProgress);
- }
- }
-
- return(machFPCurStatePtr == machCurStatePtr);
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Routines to set up and return from signal handlers.
- *
- * In order to call a handler four things must be done:
- *
- * 1) The current state of the process must be saved so that when
- * the handler returns a normal return to user space can occur.
- * 2) The user stack must be set up so that the signal number and the
- * the signal code are passed to the handler.
- * 3) Things must be set up so that when the handler returns it returns
- * back into the kernel so that state can be cleaned up.
- * 4) The trap stack that was created when the kernel was entered and is
- * used to return a process to user space must be modified so that
- * the signal handler is called instead of executing the
- * normal return.
- *
- * The last one is done by simply changing the program counter where the
- * user process will execute on return to be the address of the signal
- * handler and the user stack pointer to point to the proper place on
- * the user stack. The first three of these are accomplished by
- * setting up the user's registers properly. The return address register is the
- * return address where the handler will start executing upon return. But
- * this is just the address of a trap instruction that is stored on the stack
- * below. Thus when a handler returns it will execute a trap instruction
- * and drop back into the kernel.
- */
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * SetupSigHandler --
- *
- * Save machine state on the users stack and set up the exception stack
- * so that the user will call the signal handler on return. In order to
- * Results:
- * None.
- *
- * Side effects:
- * Signal stack set up and saved.
- *
- * ----------------------------------------------------------------------------
- */
- static void
- SetupSigHandler(procPtr, sigStackPtr, pc)
- register Proc_ControlBlock *procPtr;
- register SignalStack *sigStackPtr;
- Address pc;
- {
- Mach_UserState *userStatePtr;
- unsigned usp;
-
- userStatePtr = &procPtr->machStatePtr->userState;
- usp = userStatePtr->regState.regs[SP] - sizeof(Sig_Context) -
- MACH_STAND_FRAME_SIZE;
-
- sigStackPtr->sigContext.machContext.break1Inst = 0x1000d;
- /*
- * Copy the user state onto the signal stack.
- */
- bcopy((Address)userStatePtr,
- (Address)&(sigStackPtr->sigContext.machContext.userState),
- sizeof(Mach_UserState));
- /*
- * Copy over the floating point state.
- */
- if (machFPCurStatePtr == machCurStatePtr) {
- MachGetCurFPState(machCurStatePtr);
- }
- bcopy((Address)procPtr->machStatePtr->userState.regState.fpRegs,
- (Address)sigStackPtr->sigContext.machContext.fpRegs,
- MACH_NUM_FPRS * sizeof(int));
- sigStackPtr->sigContext.machContext.fpStatusReg =
- procPtr->machStatePtr->userState.regState.fpStatusReg;
- /*
- * Copy the stack out to user space.
- */
- if (Vm_CopyOut(sizeof(Sig_Context), (Address)&sigStackPtr->sigContext,
- (Address)(usp + MACH_STAND_FRAME_SIZE)) != SUCCESS) {
- printf("Warning: HandleSig: No room on stack for signal, PID=%x.\n",
- procPtr->processID);
- Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
- }
- /*
- * Now set up the registers correctly.
- */
- userStatePtr->regState.regs[SP] = usp;
- if (procPtr->unixProgress != PROC_PROGRESS_NOT_UNIX) {
- int unixSignal;
- if (Compat_SpriteSignalToUnix(sigStackPtr->sigStack.sigNum,
- &unixSignal) != SUCCESS) {
- printf("Signal %d invalid in SetupSigHandler\n",
- sigStackPtr->sigStack.sigNum);
- } else {
- userStatePtr->regState.regs[A0] = unixSignal;
- }
- } else {
- userStatePtr->regState.regs[A0] = sigStackPtr->sigStack.sigNum;
- }
- userStatePtr->regState.regs[A1] = sigStackPtr->sigStack.sigCode;
- userStatePtr->regState.regs[A2] = usp + MACH_STAND_FRAME_SIZE;
- userStatePtr->regState.regs[A3] = sigStackPtr->sigStack.sigAddr;
- userStatePtr->regState.pc = pc;
- userStatePtr->regState.regs[RA] = usp + MACH_STAND_FRAME_SIZE +
- (unsigned)&((Sig_Context *)0)->machContext.break1Inst;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * ReturnFromSigHandler --
- *
- * Process a return from a signal handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Signal stack struct and size filled in the machine struct for the
- * given process.
- *
- * ----------------------------------------------------------------------------
- */
- static void
- ReturnFromSigHandler(procPtr)
- register Proc_ControlBlock *procPtr;
- {
- register Mach_State *statePtr;
- SignalStack sigStack;
-
- statePtr = procPtr->machStatePtr;
- /*
- * Copy the signal stack in.
- */
- if (Vm_CopyIn(sizeof(Sig_Context),
- (Address)(statePtr->userState.regState.regs[SP] +
- MACH_STAND_FRAME_SIZE),
- (Address) &sigStack.sigContext) != SUCCESS) {
- printf("%s Mach_Code: Stack too small to extract trap info, PID=%x.\n",
- "Warning:", procPtr->processID);
- Proc_ExitInt(PROC_TERM_DESTROYED, PROC_BAD_STACK, 0);
- }
- sigStack.sigStack.contextPtr = &sigStack.sigContext;
- /*
- * Take the proper action on return from a signal.
- */
- Sig_Return(procPtr, &sigStack.sigStack);
- /*
- * Restore user state.
- */
- bcopy((Address)&sigStack.sigContext.machContext.userState,
- (Address)&statePtr->userState, sizeof(statePtr->userState));
- /*
- * Copy in the floating point state.
- */
- bcopy((Address)sigStack.sigContext.machContext.fpRegs,
- (Address)statePtr->userState.regState.fpRegs,
- MACH_NUM_FPRS * sizeof(int));
- statePtr->userState.regState.fpStatusReg =
- sigStack.sigContext.machContext.fpStatusReg & ~MACH_FPC_EXCEPTION_BITS;
- if (machFPCurStatePtr == machCurStatePtr) {
- machFPCurStatePtr = (Mach_State *)NIL;
- }
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_ProcessorState --
- *
- * Determines what state the processor is in.
- *
- * Results:
- * MACH_USER if was at user level
- * MACH_KERNEL if was at kernel level
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- /*ARGSUSED*/
- Mach_ProcessorStates
- Mach_ProcessorState(processor)
- int processor; /* processor number for which info is requested */
- {
- if (mach_KernelMode) {
- return(MACH_KERNEL);
- } else {
- return(MACH_USER);
- }
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_GetMachineArch --
- *
- * Return the machine architecture.
- *
- * Results:
- * The machine architecture.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- int
- Mach_GetMachineArch()
- {
- return SYS_DS3100;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_GetMachineType --
- *
- * Return the machine type.
- *
- * Results:
- * 0.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- int
- Mach_GetMachineType()
- {
- return 0;
- }
-
-
- /*
- * ----------------------------------------------------------------------------
- *
- * Mach_CheckSpecialHandling--
- *
- * Forces a processor to check the special handling flag of a process.
- * This should only be called on a multiprocessor.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- * ----------------------------------------------------------------------------
- */
- void
- Mach_CheckSpecialHandling(pnum)
- int pnum; /* Processor number. */
- {
- panic("Mach_CheckSpecialHandling called for processor %d\n",pnum);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_GetNumProcessors() --
- *
- * Return the number of processors in the system. NOTE: This should
- * really be in a machine-independent area of the mach module. Note
- * further: if this is used only as a system call, it should return
- * a ReturnStatus!
- *
- * Results:
- * The number of processors is returned.
- *
- * Side effects:
- * None
- *
- *----------------------------------------------------------------------
- */
-
- int
- Mach_GetNumProcessors()
- {
- return (mach_NumProcessors);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_GetBootArgs --
- *
- * Returns the arguments out of the boot parameter structure.
- *
- * Results:
- * Number of elements returned in argv.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- int
- Mach_GetBootArgs(argc, bufferSize, argv, buffer)
- int argc; /* Number of elements in argv */
- int bufferSize; /* Size of buffer */
- char **argv; /* Ptr to array of arg pointers */
- char *buffer; /* Storage for arguments */
- {
- int i;
- int offset;
-
- bcopy(machMonBootParam.strings, buffer,
- (bufferSize < 256) ? bufferSize : 256);
- offset = (int) machMonBootParam.strings - (int) buffer;
- for(i = 0; i < argc; i++) {
- if (machMonBootParam.argPtr[i] == (char *)NULL) break;
- argv[i] = (char *) (machMonBootParam.argPtr[i] - (char *) offset);
- }
- return i;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_GetEtherAddress --
- *
- * Return the ethernet address out of the rom.
- *
- * Results:
- * Number of elements returned in argv.
- *
- * Side effects:
- * *etherAddrPtr gets the ethernet address.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_GetEtherAddress(etherAddrPtr)
- Net_EtherAddress *etherAddrPtr;
- {
- volatile unsigned *romPtr = (unsigned *)0xBD000000;
-
- etherAddrPtr->byte1 = (romPtr[0] >> 8) & 0xff;
- etherAddrPtr->byte2 = (romPtr[1] >> 8) & 0xff;
- etherAddrPtr->byte3 = (romPtr[2] >> 8) & 0xff;
- etherAddrPtr->byte4 = (romPtr[3] >> 8) & 0xff;
- etherAddrPtr->byte5 = (romPtr[4] >> 8) & 0xff;
- etherAddrPtr->byte6 = (romPtr[5] >> 8) & 0xff;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * MemErrorInterrupt --
- *
- * Handler an interrupt for the DZ device.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- MemErrorInterrupt()
- {
- unsigned short *sysCSRPtr = (unsigned short *)0xbe000000;
- unsigned short csr;
-
- csr = *sysCSRPtr;
-
- if (csr & MACH_CSR_MEM_ERR) {
- panic("Mem error interrupt\n");
- } else {
- *sysCSRPtr = MACH_CSR_VINT | csr | 0x00ff;
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_FlushCode --
- *
- * Flush the kernel code from the icache at the given address.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_FlushCode(addr, len)
- Address addr;
- unsigned len;
- {
- unsigned cacheAddr;
-
- cacheAddr = VMMACH_PHYS_UNCACHED_START - machInstCacheSize +
- ((unsigned)addr & (machInstCacheSize - 1));
- #ifdef notdef
- printf("len=%d addr=%x cacheAddr=%x\n", len, addr, cacheAddr);
- #endif
- MachCleanICache(cacheAddr, len);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_SendSignal
- *
- * Send either an illegal instruction or a floating point exception
- * to the current process.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- Mach_SendSignal(sigType)
- int sigType;
- {
- Proc_ControlBlock *procPtr;
-
- procPtr = Proc_GetActualProc();
-
- printf("Mach_SendSignal: Sending signal\n");
-
- switch ((int)sigType) {
- case MACH_SIGFPE:
- (void) Sig_Send(SIG_ILL_INST, SIG_FP_EXCEPTION,
- procPtr->processID, FALSE, (Address)0);
- break;
- case MACH_SIGILL:
- (void) Sig_Send(SIG_ILL_INST, SIG_ILL_INST_CODE,
- procPtr->processID, FALSE, (Address)0);
- break;
- default:
- panic("Mach_SendSignal: Bad signal type\n");
- break;
- }
- }
-
- void
- PrintError()
- {
- panic("Error on stack\n");
- }
-
- static void
- PrintInst(pc, inst)
- unsigned pc;
- unsigned inst;
- {
- printf("Emulating 0x%x: 0x%x\n", pc, inst);
- }
-
- static void
- SoftFPReturn()
- {
- printf("SoftFPReturn\n");
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_SigreturnStub --
- *
- * Procedure to map from Unix sigreturn system call to Sprite.
- * On the decstation, this is used for returning from a signal.
- * Note: This routine is exactly the same as MachUNIXLongJumpReturn.
- * Presumably the other routine will go away as soon as Unix
- * compatibility is working.
- *
- * Results:
- * Error code is returned upon error. Otherwise SUCCESS is returned.
- *
- * Side effects:
- * Side effects associated with the system call.
- *
- *----------------------------------------------------------------------
- */
- int
- Mach_SigreturnStub(sigContextPtr)
- struct sigcontext *sigContextPtr;
- {
- struct sigcontext sigContext;
- Mach_RegState *regsPtr;
- int dummy;
- ReturnStatus status;
- extern Mach_State *machCurStatePtr;
-
- status = Vm_CopyIn(sizeof(struct sigcontext), (Address)sigContextPtr,
- (Address)&sigContext);
- if (status != SUCCESS) {
- return(status);
- }
- regsPtr = &machCurStatePtr->userState.regState;
- regsPtr->pc = (Address)(sigContext.sc_pc - 4);
- bcopy(sigContext.sc_regs, regsPtr->regs, sizeof(sigContext.sc_regs));
- regsPtr->mflo = sigContext.sc_mdlo;
- regsPtr->mfhi = sigContext.sc_mdhi;
- bcopy(sigContext.sc_fpregs, regsPtr->fpRegs, sizeof(sigContext.sc_fpregs));
- regsPtr->fpStatusReg = sigContext.sc_fpc_csr;
- Proc_GetCurrentProc()->sigHoldMask = sigContext.sc_mask;
- return(SUCCESS);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * CheckFastRestart --
- *
- * Check if enough space was allocated for the fast restart.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- CheckFastRestart()
- {
- /* No-op on decstations for now. */
- return;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_GetRestartTableSize --
- *
- * Return the size allocated for the fast restart table area.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- Mach_GetRestartTableSize()
- {
- /* No-op on decstations for now. */
- return 0;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Mach_FastBoot --
- *
- * Do a fast reboot (using copied initialized data heap, etc.)
- *
- * Results:
- * FAILURE if we're not set up to do a fast boot. Otherwise we don't
- * return, but boot instead.
- *
- * Side effects:
- * Will probably cause fast reboot.
- *
- *----------------------------------------------------------------------
- */
- int
- Mach_FastBoot()
- {
- /* No-op on decstations for now. */
- Mach_MonPrintf("Can't do decstation fast boot yet.\n");
- return FAILURE;
- }
-